package cn.itsource.ymcc.service.impl;

import cn.itsource.ymcc.domain.AggrTermsBucket;
import cn.itsource.ymcc.domain.CourseDoc;
import cn.itsource.ymcc.mapper.HighlightResultMapper;
import cn.itsource.ymcc.query.AggrPageList;
import cn.itsource.ymcc.query.CourseDocQuery;
import cn.itsource.ymcc.repository.CourseElasticsearchRepository;
import cn.itsource.ymcc.result.JsonResult;
import cn.itsource.ymcc.result.PageList;
import cn.itsource.ymcc.service.ICourseESService;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.*;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.awt.print.Pageable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

@Service
public class CourseESServiceImpl implements ICourseESService {
    @Autowired
    private CourseElasticsearchRepository repository;
    @Autowired
    private ElasticsearchRestTemplate restTemplatel;
    @Autowired
    private HighlightResultMapper resultMapper;

    @Override
    public JsonResult search(CourseDocQuery query) {
        //第一层 query
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        //bool
        BoolQueryBuilder bool = QueryBuilders.boolQuery();

        //高级查询底层都是通过单分支语句动态拼接条件   设置查询条件
        if(StringUtils.hasText(query.getKeyword())) {
            bool.filter().add(QueryBuilders.matchQuery("name", query.getKeyword()));
        }
        if(StringUtils.hasText(query.getGradeName())) {
            bool.filter().add(QueryBuilders.termQuery("gradeName", query.getGradeName()));
        }
        queryBuilder.withQuery(bool);//到此为止都在做查询条件的构建

        //添加排序查询
        if(StringUtils.hasText(query.getOrderField())){
            SortOrder sortOrder = SortOrder.ASC;
            //不区分大小写判断
            if("desc".equalsIgnoreCase(query.getOrderType())){
                sortOrder = SortOrder.DESC;
            }
            SortBuilder sortBuilder = SortBuilders.fieldSort(query.getOrderField()).order(sortOrder);
            queryBuilder.withSort(sortBuilder);
        }

        //设置聚合
        queryBuilder.addAggregation(AggregationBuilders
                .terms("gradeNameAgg")  //取别名
                .field("gradeName")       //要聚合的字段名
                .order(BucketOrder.count(false))//排序
                .size(30));//要取的条数  可以不设置

        //添加分页
        //注意：SpringDataElasticsearch的当前页码是从0开始的
        PageRequest of = PageRequest.of(query.getPageNo() <= 0?0:query.getPageNo()-1, query.getPageSize());
        queryBuilder.withPageable(of);

        HighlightBuilder.Field  highlightField = new HighlightBuilder.Field("name")
                .preTags("<span style='color:red'>")
                .postTags("</span>");

        queryBuilder.withHighlightFields(highlightField);





//        Page<CourseDoc> page = repository.search(queryBuilder.build());//不支持
        AggregatedPage<CourseDoc> page = restTemplatel.queryForPage(queryBuilder.build(), CourseDoc.class, resultMapper);
        System.out.println("当前页码："+page.getNumber());
        System.out.println("每页条数："+page.getSize());
        System.out.println("总条数："+page.getTotalElements());
        System.out.println("总页数："+page.getTotalPages());
        System.out.println("当前页条数："+page.getNumberOfElements());
        //封装返回数据
        List<CourseDoc> content = page.getContent();
//        PageList<CourseDoc> pageList = new PageList<>(page.getTotalElements(),content);
        Map<String, List<AggrTermsBucket>> aggrResult = getAggrResult(page);

        AggrPageList<CourseDoc> objectAggrPageList = new AggrPageList<CourseDoc>(page.getTotalElements(),content,aggrResult);
        return JsonResult.success().setData(objectAggrPageList);
    }

    private Map<String, List<AggrTermsBucket>> getAggrResult(AggregatedPage<CourseDoc> page) {
        //用来封装聚合结果
        Map<String,List<AggrTermsBucket>> aggrMap = new HashMap<>();

        //遍历聚合结果
        Aggregations aggregations = page.getAggregations();

        Map<String, Aggregation> stringAggregationMap = aggregations.asMap();

        Set<Map.Entry<String, Aggregation>> entries = stringAggregationMap.entrySet();

        entries.forEach(e->{
            //集合的名字
            String key = e.getKey();
            //集合的值的处理
            ParsedStringTerms value = (ParsedStringTerms)e.getValue();
            List<? extends Terms.Bucket> buckets = value.getBuckets();

            //使用lomda 把  List<StringTerms.Bucket>  转成  List<AggrTermsVo>
            List<AggrTermsBucket> aggrTermsVos = buckets.stream().map(bucket -> {
                return new AggrTermsBucket(bucket.getKeyAsString(), bucket.getDocCount());
            }).collect(Collectors.toList());

            aggrMap.put(key, aggrTermsVos);
        });
        return aggrMap;
    }
}
